﻿namespace Renci.iRods.Studio.ViewModels
{
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using Renci.iRods.Studio.Common;
    using Renci.iRods.Studio.ViewModels;
    using System.Windows.Input;
    using Renci.iRods.Studio.Models;
    using Microsoft.Practices.ServiceLocation;
    using Renci.iRods.Studio.Common.BaseClasses;
    using Microsoft.Practices.Prism.Events;
    using Renci.iRods.Studio.Common.Events;
    using Renci.iRods.Studio.Resources;
    using Microsoft.Practices.Prism.Commands;
    using Microsoft.Practices.Prism.Interactivity.InteractionRequest;

    public class ShellWindowModel : ViewModelBase, IDisposable
    {
        private ConnectionChnagedEvent _connectionChangedEvent;

        private IRodsConnection _currentConnection;

        private Profile _profile;

        private bool _isBusy;
        /// <summary>
        /// Gets or sets whether shell is busy.
        /// </summary>
        /// <value>
        /// The property.
        /// </value>
        public bool IsBusy
        {
            get
            {
                return this._isBusy;
            }
            set
            {
                this._isBusy = value;
                this.NotifyOfPropertyChange(() => this.IsBusy);
            }
        }

        private ViewModelBase _statusBar = new StatusBarNotConnectedViewModel();
        /// <summary>
        /// Gets or sets the status bar.
        /// </summary>
        /// <value>
        /// The status bar.
        /// </value>
        public ViewModelBase StatusBar
        {
            get { return this._statusBar; }
            set
            {
                this._statusBar = value;
                this.NotifyOfPropertyChange(() => this.StatusBar);
            }
        }

        public IEnumerable<ConnectionProfile> FavoriteConnections
        {
            get
            {
                return from conn in this._profile.ConnectionProfiles
                       where conn.IsFavorite
                       select conn;
            }
        }

        public ICommand ConnectCommand
        {
            get { return new DelegateCommand<ConnectionProfile>(param => this.Connect(param)); }
        }

        public ICommand ShowConnectionManagerCommand
        {
            get { return new RelayCommand(() => this.ShowConnectionManager()); }
        }

        public ICommand ShowConnectionSelectionCommand
        {
            get { return new RelayCommand(() => this.ShowConnectionSelection()); }
        }

        /// <summary>
        /// Gets the interaction request for displaying connection manager dialog
        /// </summary>
        public InteractionRequest<DialogWindowPopup> ShowConnectionManagerRequest { get; private set; }

        /// <summary>
        /// Gets the interaction request for displaying connection manager dialog
        /// </summary>
        public InteractionRequest<DialogWindowPopup> ShowConnectionSelectionRequest { get; private set; }

        /// <summary>
        /// Gets the interaction request for displaying message dialog box
        /// </summary>
        public InteractionRequest<Notification> ShowMessageBoxRequest { get; private set; }

        public ShellWindowModel()
        {
            var eventAggregator = ServiceLocator.Current.GetInstance<IEventAggregator>();
            this._connectionChangedEvent = eventAggregator.GetEvent<ConnectionChnagedEvent>();
            this._connectionChangedEvent.Subscribe(OnConnectionChanged);

            this.ShowConnectionManagerRequest = new InteractionRequest<DialogWindowPopup>();
            this.ShowConnectionSelectionRequest = new InteractionRequest<DialogWindowPopup>();
            this.ShowMessageBoxRequest = new InteractionRequest<Notification>();

            this._profile = ServiceLocator.Current.GetInstance<Profile>();
            
            this._profile.PropertyChanged += delegate(object sender, System.ComponentModel.PropertyChangedEventArgs e)
            {
                //  Update FavoriteConnections if connection profiles changed
                if (e.PropertyName == "ConnectionProfiles")
                {
                    this.NotifyOfPropertyChange(() => this.FavoriteConnections);
                }
            };
        }



        private void Connect(ConnectionProfile connectionProfile)
        {
            this.Disconnect();

            try
            {
                this._currentConnection = new IRodsConnection(connectionProfile.ConnectionInfo);
                this._currentConnection.Open();
                ApplicationState.Current.Connection = this._currentConnection;
            }
            catch (Exception exp)
            {
                ApplicationState.Current.Connection = null;
                this.ShowMessageBoxRequest.Raise(new Notification() { Content = string.Format(Errors.ConnectionErrorMessage, exp.Message), Title = Errors.ErrorTitleMessage });
            }
        }

        private void ShowConnectionManager()
        {
            this.ShowConnectionManagerRequest.Raise(new DialogWindowPopup(true, new ConnectionProfileManagerViewModel()));
        }

        private void ShowConnectionSelection()
        {
            this.ShowConnectionSelectionRequest.Raise(new DialogWindowPopup(true, new ConnectionProfileSelectionViewModel()),
                (d) =>
                {
                    var c = d.Content as ConnectionProfileSelectionViewModel;

                    if (c.SelectedConnectionProfile != null && c.SelectedConnectionProfile.IsValid)
                    {
                        this.Connect(c.SelectedConnectionProfile);
                    }
                }
            );
        }

        /// <summary>
        /// Disconnects currently active connection.
        /// </summary>
        /// <returns></returns>
        private void Disconnect()
        {
            if (this._currentConnection != null)
            {
                this._currentConnection.Close();
                this._currentConnection = null;
                ApplicationState.Current.Connection = null;
            }
        }

        private void OnConnectionChanged(IRodsConnection connection)
        {
            if (connection == null)
            {
                this.StatusBar = new StatusBarNotConnectedViewModel();
            }
            else
            {
                this.StatusBar = new StatusBarConnectedViewModel(connection);
            }
        }

        #region IDisposable Members

        private bool _disposed = false;

        /// <summary>
        /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged ResourceMessages.
        /// </summary>
        public void Dispose()
        {
            Dispose(true);

            GC.SuppressFinalize(this);
        }

        /// <summary>
        /// Releases unmanaged and - optionally - managed resources
        /// </summary>
        /// <param name="disposing"><c>true</c> to release both managed and unmanaged resources; <c>false</c> to release only unmanaged ResourceMessages.</param>
        protected virtual void Dispose(bool disposing)
        {
            // Check to see if Dispose has already been called.
            if (!this._disposed)
            {
                // If disposing equals true, dispose all managed
                // and unmanaged ResourceMessages.
                if (disposing)
                {

                    if (this._currentConnection != null)
                    {
                        this._currentConnection.Dispose();
                        this._currentConnection = null;
                    }
                }

                // Note disposing has been done.
                this._disposed = true;
            }
        }

        /// <summary>
        /// Releases unmanaged resources and performs other cleanup operations before the
        /// <see cref="Session"/> is reclaimed by garbage collection.
        /// </summary>
        ~ShellWindowModel()
        {
            // Do not re-create Dispose clean-up code here.
            // Calling Dispose(false) is optimal in terms of
            // readability and maintainability.
            Dispose(false);
        }

        #endregion
    }
}
